#pragma once

#include <map>
#include <set>
#include <list>
#include <vector>
#include <string>
#include <fstream>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <ext/hash_map>
#include <string.h>
#include <sys/stat.h>
#include <algorithm>
//#include <math.h>

#include "Contig.h"
#include "CommonFunction.h"
#include "Gap.h"
#include "PathNode.h"
#include "ConnectedNode.h"
#include "Configure.h"
#include "ConfigReader.h"

using namespace std;
using namespace __gnu_cxx; 

struct eqName
{
  bool operator()(const char* s1, const char* s2) const
  {
    return strcmp(s1,  s2) == 0;
  }
};

struct smallerDistance {
    bool operator()(ConnectedNode *a, ConnectedNode *b) const {
		return a->GetMinDis() > b->GetMinDis();
    }
};

#ifndef DEBUG
#define DEBUG
#endif

class ContigGraphAnalyzer
{
public:
	ContigGraphAnalyzer(void);
	virtual ~ContigGraphAnalyzer(void);

	// Attributes
public:
	map<int, Contig*> *m_contigs;				// the set of contigs
	map<string, Contig*> *m_contigsName;			// map of contigs using name
	int m_numOfContig;							// total number of contigs
	double m_avgCov;			// the average coverage of contig
	double m_sumLength;				// the total length of assembly
	int m_fillType;				// greedy or stringent(only consider unique path)
	int m_fileType;
	int m_multiPath;			// the number of gaps which have multi paths
	string m_outputPath;		// the output folder 
	int m_disconnectedGap;		// number of disconnected gaps
	int m_totalFilledGaps;

private:
	map<string, list<int>* > *m_headList;			// the map to save all the first kmer of each contig, contigID orientation
	map<string, list<int>* > *m_tailList;			// the map to save all the last kmer of each contig
	hash_map<const char*, list<int>*, hash<const char*>, eqName> *m_headHashMap;
	hash_map<const char*, list<int>*, hash<const char*>, eqName> *m_tailHashMap;
	int m_totalGaps;
	double m_covThreshold;								// the threshold of coverage of contigs

	// gap fill related variables
	string m_constraints;							// the constraints string content in quadratic program
	string m_aimStringQuad;							// the string of quadratic part in aim function
	string m_aimStringLinear;						// the string of linear part in aim function
	string m_variableString;						// the string of all the variables
	vector<vector<int>*> *m_aimQuadValue;			// the quadratic value of variables in aim function
	vector<int> *m_aimLinearValue;					// the linear value of variables in aim function
	string m_simplePath;							// save all simple path

	// methods
public:
	// analyze velvet graph file
	int ReadVelvetGraphFile( string graphFileName );
	// analyze SOAPdenovo file
	int ReadSoapFile( string graphFileName, string contigFileName );	
	// analyze SOAPdenovo graph file
	int ReadSoapGraphFile( string graphFileName );	
	// analyze ABySS file
	int ReadAbyssFile( string graphFileName, string contigFileName );
	// analyze ABySS graph file
	int ReadAbyssGraphFile( string graphFileName );	
	// find interesting contigs
	void FindRepeats();
	// print dot file of current graph
	void PrintDotFile();
	// read scaffold file
	void ReadScaffoldFile( string fileName );
	// calculate average coverage
	void CalculateAvgCov();
	// read contig fasta file
	int ReadContigFasta( string fileName );
	// print edges of all contigs
	void PrintEdges();
	// set kmer size
	void SetKmer( int kmer );
	// set coverage
	void SetCovThreshold( double cov );
	// analyze subgraph for each gaps
	void AnalyzeGaps( string scafFileName );
	// read SOAPdenovo file to get kmer size
	int GetKmerOfSOAP( string prefix );
	// print graph around vector
	int PrintGraphAroundVector();

private:
	// print certain edges
	void PrintEdges( map<int, pair<Contig*, int> > *edges );
	// get contig information
	void GetVelvetContigInfo( string line, string plusSeq, string minusSeq );
	// get edge information
	void GetVelvetEdgeInfo( string line );
	// print edges to file
	int PrintEdges( FILE *file, Contig *c, map<int, pair<Contig*, int> > *edges, int type, set<Contig*> *subgraph );
	// print subgraph
	int PrintSubgraph( int id, set<Contig*> *graph, string name );
	// generate Gap
	Gap* GenerateGap( string preline, string nextline );
	// fill in gaps
	void FillGap( Gap *gap );
	// find path in iterative way
	bool FindPath( PathNode *node, list<string> *paths, Gap *gap, bool isStart );
	// select proper path to fill the gap
	void SeletePath( Gap *gap, list<string> *paths );
	// insert the kmer into map
	void InsertKmerIntoMap( string kmer, map<string, list<int>* >* kmerList, int contigID, int ori );
	void InsertKmerIntoHashMap( string kmer, hash_map<const char*, list<int>*, hash<const char*>, eqName> *kmerHashMap, int contigID, int ori );
	// get two kmers from the line
	void GetTwoKmer( string line, string &firstKmer, string &lastKmer );
	// find all overlap information of SOAPdenovo
	void FindOverlapOfSOAP();
	// generate the subgraph for each gap
	void GenSubgraph( Gap *gap );
	// search the path in iterative way
	void GetPossibleNodes( Gap *gap, int startContigType, set<ConnectedNode*> *nodeSet );
	// print connected gaps
	void PrintConnectedGaps( vector<Gap*> *gaps );

	// vector related funcitons 
	bool CheckIfNormal( Contig *head, Contig *tail, string arrowHead, string arrowTail );

	// fill gaps
	bool SimplyFillGap( Gap *gap, int way );
	void GenQuadProg( set<Gap*> *gaps, int id );
	void CreateVariable( Contig *c, map<int, pair<Contig*, int> > *edges, int type, set<Contig*> *subgraph, vector<int> *variables, string &problemStr, vector<int> *scafVar );
	void GenAimFunction( Gap *gap, string &problemStr );
	void GenInOutEquation( Contig *c, string &problemStr );
	void GenCopyNumberConstraints( list<int> *var, Contig *c, string &problemStr );
	void GenEqualOneConstraints( list<int> *var, Contig *c, string &problemStr );
	void AddAimLinearCoef( int value, int id );
	void AddAimQuadCoef( int value, int x, int y );
	void AddPunishFunction( vector<int> *scafVar, vector<int> *var );			// add the punishment function
	// simplify graph
	void SimplifyGraph(set<Contig*> *nodes);
	bool CheckBubble( set<Contig*> *nodes );		// check if the graph contain bubble
	bool IfBelongToBubble( Contig *c, set<Contig*> *nodes);		// check if current contig c belong to a bubble
	bool CheckSimplePath( set<Contig*> *nodes );		// check if the graph contain simple path
	bool IfBelongToSimplePath( Contig *c, set<Contig*> *nodes, int ori);		// check if current contig c belong to a simple path
	void OutputSimplePath( string fileName );

	// naive method to fill the gap one by one
	void GenerateGapSeq( Gap *g );
};

// comparison, not case sensitive.
bool small_gap ( Gap *first, Gap *second)
{
	return first->GetGapSize() < second->GetGapSize(); 
}


